#include "sdk.h"
#include "manager.h"
#include "menuitemsmanager.h"
#include <wx/regex.h>

namespace {
  wxRegEx reInsert( _T( "([0-9]+):.+" ) );
}

MenuItemsManager::MenuItemsManager( bool autoClearOnDestroy )
  : m_AutoClearOnDestroy( autoClearOnDestroy ) {
}

MenuItemsManager::~MenuItemsManager() {
  if( m_AutoClearOnDestroy ) {
    Clear();
    m_MenuItems.Clear();
  }
}


wxMenuItem* MenuItemsManager::Add( wxMenu* parent, int id, const wxString& caption, const wxString& helptext ) {
  if( !parent ) {
    return nullptr;
  }
  wxMenuItem* ni = new wxMenuItem( parent, id, caption, helptext );
  m_MenuItems.Add( ni );
  parent->Append( ni );
  return ni;
}


wxMenuItem* MenuItemsManager::Insert( wxMenu* parent, int index, int id, const wxString& caption, const wxString& helptext ) {
  if( !parent ) {
    return nullptr;
  }
  wxMenuItem* ni = new wxMenuItem( parent, id, caption, helptext );
  m_MenuItems.Add( ni );
  parent->Insert( index, ni );
  return ni;
}


void MenuItemsManager::Clear() {
  for( unsigned int i = 0; i < m_MenuItems.Count(); ++i ) {
    wxMenuItem* ni = m_MenuItems[i];
    wxMenu* menu = ni->GetMenu();
    wxMenu* subMenu = ni->GetSubMenu();
    if( menu ) {
      if( !subMenu || subMenu->GetMenuItemCount() == 0 ) {
        menu->Delete( ni );
      }
    }
  }
  m_MenuItems.Clear();
}


int MenuItemsManager::CreateFromString( const wxString& menuPath, int id ) {
  wxMenuBar* mbar = Manager::Get()->GetAppFrame()->GetMenuBar();
  wxMenu* menu = nullptr;
  size_t pos = 0;
  while( true ) {
    while( pos < menuPath.Length() && menuPath.GetChar( pos ) == _T( '/' ) ) {
      ++pos;
    }
    size_t nextPos = pos;
    while( nextPos < menuPath.Length() && menuPath.GetChar( ++nextPos ) != _T( '/' ) )
      ;
    wxString current = menuPath.Mid( pos, nextPos - pos );
    if( current.IsEmpty() ) {
      break;
    }
    bool isLast = nextPos >= menuPath.Length();
    bool insert = false;
    unsigned long insertIndex = 0;
    if( reInsert.Matches( current ) ) {
      wxString indexS = reInsert.GetMatch( current, 1 );
      if( indexS.ToULong( &insertIndex, 10 ) ) {
        current.Remove( 0, indexS.Length() + 1 );
        insert = true;
      }
    }
    if( !menu ) {
      if( isLast ) {
        return 0;
      }
      int menuPos = mbar->FindMenu( current );
      if( menuPos == wxNOT_FOUND ) {
        menu = new wxMenu();
        mbar->Insert( insert ? insertIndex : mbar->GetMenuCount() - 2, menu, current );
      } else
      { menu = mbar->GetMenu( menuPos ); }
    } else {
      bool needsSep = current.StartsWith( _T( "-" ) );
      if( needsSep ) {
        current.Remove( 0, 1 );
      }
      int existingID = menu->FindItem( current );
      if( existingID != wxNOT_FOUND ) {
        if( isLast ) {
          return existingID;
        }
        wxMenuItem *item = menu->FindChildItem( existingID );
        if( item ) {
          wxMenu* existingMenu = item->GetSubMenu();
          if( existingMenu ) {
            menu = existingMenu;
          } else
          { return 0; }
        } else
        { return 0; }
      } else {
        if( needsSep ) {
          wxMenuItem* item = new wxMenuItem( menu, wxID_SEPARATOR );
          menu->Insert( insert ? insertIndex : menu->GetMenuItemCount(), item );
        }
        if( current.IsEmpty() ) {
          break;
        }
        if( isLast ) {
          Insert( menu, insert ? insertIndex : menu->GetMenuItemCount(), id, current, wxEmptyString );
          return id;
        } else {
          wxMenu* sub = new wxMenu;
          wxMenuItem* item = new wxMenuItem( menu, -1, current, wxEmptyString, wxITEM_NORMAL, sub );
          menu->Insert( insert ? insertIndex : menu->GetMenuItemCount(), item );
          menu = sub;
        }
      }
    }
    pos = nextPos;
  }
  return 0;
}
